package com.ts.api.module.api.wake.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 平滑加权轮询（非线程安全）
 */
public class SmoothWeightedRoundRobin<T> {

    private List<Item<T>> list = new ArrayList<>();

    public void add(int weight, T value) {
        Item<T> item = new Item<>(weight, 0, value);
        list.add(item);
    }

    public T next() {
        for (Item<T> item : list) {
            item.addCurrentWeight(item.weight);
        }
        Item<T> max = list.getFirst();
        for (Item<T> item : list) {
            if (item.currentWeight > max.currentWeight) {
                max = item;
            }
        }
        int totalWeight = this.getTotalWeight();
        max.addCurrentWeight(-totalWeight);
        return max.value;
    }

    /**
     * 指定
     */
    public void designatedNext(T value) {
        Item<T> max = null;
        for (Item<T> item : list) {
            if (Objects.equals(item.value, value)) {
                max = item;
                break;
            }
        }
        if (max == null) {
            return;
        }
        for (Item<T> item : list) {
            item.addCurrentWeight(item.weight);
        }
        int totalWeight = this.getTotalWeight();
        max.addCurrentWeight(-totalWeight);
    }

    private int getTotalWeight() {
        int totalWeight = 0;
        for (Item<T> item : list) {
            totalWeight += item.weight;
        }
        return totalWeight;
    }

    private static class Item<T> {
        private final int weight;
        private int currentWeight;
        private final T value;

        private Item(int weight, int currentWeight, T value) {
            this.weight = weight;
            this.currentWeight = currentWeight;
            this.value = value;
        }

        public void addCurrentWeight(int num) {
            // 处理极限情况溢出问题
            long result = (long) this.currentWeight + (long) num;
            if (result > Integer.MAX_VALUE) {
                result = Integer.MAX_VALUE;
            }
            if (result < Integer.MIN_VALUE) {
                result = Integer.MIN_VALUE;
            }
            this.currentWeight = (int) result;
        }
    }

    public static void main(String[] args) {

        SmoothWeightedRoundRobin<String> wrr = new SmoothWeightedRoundRobin<>();
        wrr.add(4, "4");
        wrr.add(10, "10");
        wrr.add(6, "6");
        for (int i = 0; i < 40; i++) {
            if (i % 10 == 0) {
                System.out.println("------------------");
            }
            System.out.println(wrr.next());
        }

        System.out.println("============================");

        SmoothWeightedRoundRobin<String> wrr2 = new SmoothWeightedRoundRobin<>();
        wrr2.add(4, "4");
        wrr2.add(10, "10");
        wrr2.add(6, "6");
        for (int i = 0; i < 10; i++) {
            wrr2.designatedNext("10");
            System.out.println("10");
        }
        for (int i = 0; i < 30; i++) {
            if (i % 10 == 0) {
                System.out.println("------------------");
            }
            System.out.println(wrr2.next());
        }

    }

}
